package org.example.cicdi.service.impl.third;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import org.example.cicdi.enums.EnumWhiteColumnAnnotation;
import org.example.cicdi.enums.EnumWhiteTableAnnotation;
import org.example.cicdi.service.impl.ext.FieldAnnotationServiceExt;
import org.example.cicdi.service.impl.org.TableAnnotationService;
import org.example.cicdi.service.impl.second.FieldfacaService;
import org.example.cicdi.service.impl.second.TbfacaService;
import org.example.cicdi.service.impl.third.handlewebvo.HandleWebVo;
import org.example.cicdi.service.impl.third.handlewebvo.HandleWebVo2;
import org.example.cicdi.utils.HttpUtils;
import org.example.codegenerate.modelext.WebVo.Enum.EnumModelType;
import org.example.codegenerate.modelext.WebVo.Enum.EnumTableType;
import org.example.codegenerate.modelext.WebVo.annotation.table.TVo;
import org.example.codegenerate.modelext.WebVo.annotation.table.WVo;
import org.example.codegenerate.modelext.WebVo.domian.column.ColumnVoDomain;
import org.example.codegenerate.modelext.WebVo.domian.table.TableVoDomain;
import org.example.codegenerate.modelext.WebVo.domian.table.WebModelVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;

import javax.persistence.Table;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

@Slf4j
@Service
public class CodeServiceExtSecond implements ApplicationRunner {
	/*
	 * ManyToOne：org.jeecg.modules.cicdi.jpa.project.child； OneToMany:org.jeecg.modules.cicdi.jpa.project.parent
	 * 2个标签不要嵌套使用，否则死循环
	 */
	private static final String BASE_PACKAGE = "org.example.userdefine";
	
    private static final String RESOURCE_PATTERN = "/**/*.class";
    
    @Autowired
    private List<TableAnnotationService>tableServices;
    
    @Autowired
    private List<FieldAnnotationServiceExt>fieldServices;
	@Autowired
	private TbfacaService tbfacaService;
	@Autowired
	private FieldfacaService fieldfacaService;

	@Value("${includedeployway}")
	private String includedeployway;

	@Override
	public void run(ApplicationArguments args) throws Exception {

		//1.读取所有需要生成代码的jpa类
		List<Class<?>> list = queryAllJpa();
		if (CollectionUtils.isEmpty(list)) {
			return;
		}
		//OnlyforTestStandards(list);
		List<WebModelVo> webModelVoList = new ArrayList<>();
		//先处理主表部分
		for (Class<?> cl : list) {
			if (cl.getAnnotation(WVo.class) != null) {
				//说明是主表.主表可能在子表先处理的时候，在集合中先找一下webvo
				WebModelVo wvo = new WebModelVo();
				if(cl.getAnnotation(Table.class)!=null){
					wvo.getTableVoDomain().setTableName(cl.getAnnotation(Table.class).name());
				}else {
					wvo.getTableVoDomain().setTableName(cl.getSimpleName());
				}

				webModelVoList.add(wvo);
				/*
				Optional<WebModelVo> opwvo=webModelVoList.stream()
								.filter(x->x.getTableVoDomain().getTableName()==cl.getAnnotation(Table.class).name())
										.findFirst();
				if(opwvo.isPresent()){
					//wvo=opwvo.get();
					break;
				}else {
					wvo=new WebModelVo();
					wvo.getTableVoDomain().setTableName(cl.getAnnotation(Table.class).name());
					webModelVoList.add(wvo);
				}*/
				HandleWebVo handleWebVo=new HandleWebVo2();
				//handleWebVo(cl, wvo);//将WVO的内容，处理在WebVO中
				handleWebVo.handleWebVo(cl, wvo);

				//处理的时候，不会碰到ManyToOne，OneToOne，JoinColumn等
				//tbfacaService.handleTableVo(cl, wvo.getTableVoDomain());
				tbfacaService.handleTableVo(cl, wvo);
				//fieldfacaService.handleFieldVo(cl, wvo.getTableVoDomain(), webModelVoList);
				fieldfacaService.handleFieldVo(cl, wvo, webModelVoList);
			}
		}
		//处理子表部分，主子表的差异，主要是是否有WVO的注解，如果有WVO的注解，那么就是主表，如果没有这个WVO的注解，只有TVO注解，那么就是子表
		for (Class<?> cl : list) {
			if (cl.getAnnotation(WVo.class) == null) {
				//是子表，但是在一开始不知道是哪一个的子表。先处理TableVoDomain。然后在ManyToOne的地方找它的父亲

				/*TableVoDomain tableVoDomain = new TableVoDomain();
				tbfacaService.handleTableVo(cl, tableVoDomain);//先把表的信息赋值给TableVoDomain。
				fieldfacaService.handleFieldVo(cl, tableVoDomain, webModelVoList);*/
				if(cl.getSimpleName().contains("DefaultTestOrderProduct")){
					int j=1;
				}
				log.info("当前正在处理的子表为{}:"+cl.getSimpleName());
				WebModelVo webModelVo=new WebModelVo();
				tbfacaService.handleTableVo(cl, webModelVo);//先把表的信息赋值给TableVoDomain。
				fieldfacaService.handleFieldVo(cl, webModelVo, webModelVoList);
			}
		}
		//统一处理一下WVO中的fieldRowNum，在前面设置的是formTemplate.前面设置不管他，在这个地方进行重新设置，这个是容错性处理
		for(WebModelVo wvo:webModelVoList){
			//实际上是maintable是设置了2. 其他表采用默认值，子表不设置
			if(wvo.getTableVoDomain().getEnumTableType()== EnumTableType.MAINTABLE){
				wvo.getTableVoDomain().setFormTemplate(String.valueOf(EnumModelType.MANY.getCode()));
			}
		}

//		for (WebModelVo wvo : webModelVoList) {
//			sortWebModelVo(wvo);
//			replacenullfrom(wvo);
//			log.info("jpa对象：{}，字符串发送：{}", wvo.getTableVoDomain().getTableName(), new Gson().toJson(wvo));
//			//3.调用远程服务
//			try {
//				String result = "";
//				if (wvo.getModeltype() == EnumModelType.MANY) {
//					String urlOneToMany = "http://localhost:8099/jeecg-boot/online/codeGenerateonetomanytable";
//					result = HttpUtils.sendPost(urlOneToMany, wvo);
//				}
//				if (wvo.getModeltype() == EnumModelType.ONE) {
//					String urlOneTable = "http://localhost:8099/jeecg-boot/online/codeGeneratesingletablewithouttree";
//					result = HttpUtils.sendPost(urlOneTable, wvo);
//				}
//				if (wvo.getModeltype() == EnumModelType.TREE) {
//					String urlOneTableWithTree = "http://localhost:8099/jeecg-boot/online/codeGeneratesingletablewithtree";
//					result = HttpUtils.sendPost(urlOneTableWithTree, wvo);
//				}
//				log.info(result);
//			}catch (Exception ex){
//				log.error(ex.toString());
//			}
//		}
		for (WebModelVo wvo : webModelVoList) {
			sortWebModelVo(wvo);
			replacenullfrom(wvo);
			log.info("jpa对象：{}，字符串发送：{}", wvo.getTableVoDomain().getTableName(), new Gson().toJson(wvo));
			//3.调用远程服务
			try {
				String result = "";
				if (wvo.getModeltype() == EnumModelType.MANY) {
					//String urlOneToMany = "http://localhost:8099/jeecg-boot/online/codeGeneratesingletablewithouttree";
					String urlOneToMany = "http://localhost:8080/jeecg-boot/online/codeGeneratecomplex";
					result = HttpUtils.sendPost(urlOneToMany, wvo);
				}
				if (wvo.getModeltype() == EnumModelType.ONE) {
					//String urlOneTable = "http://localhost:8099/jeecg-boot/online/codeGeneratesingletablewithtree";
					String urlOneTable = "http://localhost:8080/jeecg-boot/online/codeGeneratecomplex";
					result = HttpUtils.sendPost(urlOneTable, wvo);
				}
				if (wvo.getModeltype() == EnumModelType.TREE) {
					//String urlOneTableWithTree = "http://localhost:8099/jeecg-boot/online/codeGenerateonetomanytable";
					String urlOneTableWithTree = "http://localhost:8080/jeecg-boot/online/codeGeneratecomplex";
					result = HttpUtils.sendPost(urlOneTableWithTree, wvo);
				}
				log.info(result);
			}catch (Exception ex){
				log.error(ex.toString());
			}
		}
	}

	private void OnlyforTestStandards(List<Class<?>> list) {
		/*for(int i=0;i<list.size();i++){
			if(((Class<?>)list[i]).getAnnotation(WVo.class).packageName().equalsIgnoreCase("standardcicdi")){
				list.remove(i);
			}
		}*/
		Iterator<Class<?>> iterator=list.iterator();
		while (iterator.hasNext()){
			Class<?> cl=iterator.next();
			//先把所有子表删掉
			if(cl.getAnnotation(TVo.class).entityName().equalsIgnoreCase("TestOrderProduct")){
				iterator.remove();
			}
			//然后在主表中，把不是standardcicdi的删除掉
			if(cl.getAnnotation(WVo.class)!=null) {
				/*if (!cl.getAnnotation(WVo.class).packageName().equalsIgnoreCase("standardcicdi")) {
					iterator.remove();
				}*/
			}
		}
	}

	private void replacenullfrom(WebModelVo wvo) {
		//通过反射，将是""的，全部替换为null

	}

	private void sortWebModelVo(WebModelVo wvo) {
		wvo.getTableVoDomain().getColumnVoDomainList().sort(new Comparator<ColumnVoDomain>() {
			@Override
			public int compare(ColumnVoDomain o1, ColumnVoDomain o2) {
				return o1.getPageVo().getOrderNum()>o2.getPageVo().getOrderNum()?1:o1.getPageVo().getOrderNum()==o2.getPageVo().getOrderNum()?0:-1;
			}
		});
		for(TableVoDomain tableVoDomain:wvo.getTableVoDomain().getSonTabeleVoDomain()){
			tableVoDomain.getColumnVoDomainList().sort(new Comparator<ColumnVoDomain>() {
				@Override
				public int compare(ColumnVoDomain o1, ColumnVoDomain o2) {
					return o1.getPageVo().getOrderNum()>o2.getPageVo().getOrderNum()?1:o1.getPageVo().getOrderNum()==o2.getPageVo().getOrderNum()?0:-1;
				}
			});
		}

	}

	private void findMainFromList(Class<?> cl,List<WebModelVo> webModelVoList){

	}
	public WebModelVo handleWebVo(Class<?>cl, WebModelVo model) {
		WVo vo = cl.getAnnotation(WVo.class);
		if (vo == null) {
			return model;
		}

		if (model == null) {
			model = new WebModelVo();
		}
		//为了保证不重复，将packagename加上了entityName
		//model.setPackageName(vo.packageName());
		/*if(vo.packageName().equalsIgnoreCase("")){
			//设置默认值
			model.setPackageName(cl.getSimpleName().toLowerCase());
		}else {
			model.setPackageName(vo.packageName());
		}*/
		if(vo.destinationOutPutDir().equalsIgnoreCase("")){
			model.setDestinationOutPutDir("D:\\eclipse2018-workspace\\jeecg-boot\\"+cl.getSimpleName().toLowerCase());
		}else {
			model.setDestinationOutPutDir(vo.destinationOutPutDir());
		}

		model.setFrontDestionOutPutDir(vo.frontDestionOutPutDir());

		model.setJformType(vo.jformType());
		model.setModeltype(vo.modeltype());
		model.setServicename(vo.servicename());

		return model;
	}

	/**
	 *
	 * @return
	 */
	private Resource[] getUserdefine(){
		Resource[] resources=null;
		try {
			//spring工具类，可以获取指定路径下的全部类
			ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

			final String User_Define_BASE_PACKAGE = "org.example.userdefine";
			String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(User_Define_BASE_PACKAGE) + RESOURCE_PATTERN;
			 resources = resourcePatternResolver.getResources(pattern);
		}catch (Exception ex){

		}
		return  resources;
	}
	/**
	 *
	 * @param sample
	 * @param userdefine
	 * @return
	 */
	private Resource[] subbine(Resource[] userdefine,Resource[] sample){
		int samplesize=sample.length;
		int userdefinesize=userdefine.length;
		Resource[] resources=new Resource[userdefinesize-samplesize];
		try {
			int count=0;

			for(int i=0;i<userdefinesize;i++){
				for(int j=0;j<samplesize;j++){
					if(!((FileSystemResource)userdefine[i]).getFile().getAbsolutePath().equalsIgnoreCase(((FileSystemResource)sample[j]).getFile().getAbsolutePath())){
						resources[count]=userdefine[i];
						count++;
						break;
					}
				}

			}
		}catch (Exception ex){
			log.error(ex.toString());
		}

		return resources;
	}
	/**
	 *
	 * @param sample
	 * @param userdefine
	 * @return
	 */
	private Resource[] combine(Resource[] sample,Resource[] userdefine){
		int samplesize=sample.length;
		int userdefinesize=userdefine.length;
		Resource[] resources=new Resource[samplesize+userdefinesize];
		for(int i=0;i<samplesize;i++){
			resources[i]=sample[i];
		}
		for(int j=0;j<userdefinesize;j++){
			resources[samplesize+j]=userdefine[j];
		}
		return resources;
	}
	/*
	 * 获取指定路径的所有jpa类
	 */
	private List<Class<?>> queryAllJpa(){
		List<Class<?>>list = new ArrayList<>();
        try {
        	//spring工具类，可以获取指定路径下的全部类
            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
			String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + RESOURCE_PATTERN;
			Resource[] resources = resourcePatternResolver.getResources(pattern);
			Resource[] userdefineresource=getUserdefine();

			//userdefineonly,sampleonly,all
        	if(includedeployway.equalsIgnoreCase("userdefineonly")){
				String BASEPACKAGE = "org.example.userdefine";
				String RESOURCEPA = "/**/*.class";
				pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASEPACKAGE) + RESOURCEPA;
				Resource[] resourcesA = resourcePatternResolver.getResources(pattern);


				BASEPACKAGE = "org.example.userdefine.示例代码";
				RESOURCEPA = "/**/*.class";
				pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASEPACKAGE) + RESOURCEPA;
				Resource[] resourcesB=resourcePatternResolver.getResources(pattern);

				resources=subbine(resourcesA,resourcesB);



				//resources = resourcePatternResolver.getResources(pattern);
				//resources=getUserdefine();
			}else if(includedeployway.equalsIgnoreCase("sampleonly")){
				String BASEPACKAGE = "org.example.userdefine.示例代码";
				String RESOURCEPA = "/**/*.class";
				pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASEPACKAGE) + RESOURCEPA;
				resourcePatternResolver.getResources(pattern);
				resources = resourcePatternResolver.getResources(pattern);
			}else {//it should be all
				if(includedeployway.equalsIgnoreCase("all")){
					String BASEPACKAGE = "org.example.userdefine";
					String RESOURCEPA = "/**/*.class";
					pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASEPACKAGE) + RESOURCEPA;
					resourcePatternResolver.getResources(pattern);
					resources = resourcePatternResolver.getResources(pattern);
					//resources=combine(resources,userdefineresource);
				}else {
					log.error("用户选择部署的方式有错误，只能在userdefineonly,sampleonly,all 3个中选择一个。");
				}
			}




            //MetadataReader 的工厂类
            MetadataReaderFactory refractory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = refractory.getMetadataReader(resource);
                //扫描到的class
                String classname = reader.getClassMetadata().getClassName();
                
                Class<?> cl = Class.forName(classname);
               /* if (cl.getAnnotation(org.hibernate.annotations.Table.class) != null) {
                	list.add(cl);
                }*/
				list.add(cl);
            }
        } catch (Exception exception) {
        }
		
		return list;
	}



	/*
	 * 构件代码生成的model对象
	 */
	private WebModelVo createModelExt(Class<?> cl) throws Exception{
		WebModelVo model = new WebModelVo();

		//1.处理类注解
		handleTableAnnotations(cl, model);

		//2.处理字段注解
		handleFieldAnnotationsExt(cl, model);
		//model.getTableVoDomain().setColumnVoDomianList(columnVoDomianList);

		return model;
	}

	private void handleTableAnnotations(Class<?> cl, WebModelVo model) {
		if (CollectionUtils.isEmpty(tableServices)) {
			return;
		}
		
		for (TableAnnotationService service : tableServices) {
			if (EnumWhiteTableAnnotation.getByCode(service.getCode()) != null) {
				service.handleTableVo(cl, model);
			}
		}
		
		log.info("类：{}，表数据封装：{}", cl.getName(), JSONObject.toJSON(model));
	}

	private void handleFieldAnnotationsExt(Class<?> cl, WebModelVo model) throws Exception{
		Field[]fields = cl.getDeclaredFields();
		if (fields == null || fields.length == 0) {
			throw new Exception("对象可用字段为空");
		}

		List<ColumnVoDomain>list = new ArrayList<>();
		for (Field field : fields) {
			field.setAccessible(true);
			for (FieldAnnotationServiceExt service : fieldServices) {
				if (EnumWhiteColumnAnnotation.getByCode(service.getCode()) != null) {
					service.handleFieldVo(field, model);
				}
			}
		}
		//return list;
	}
}
